/*	TargetedAbundanceAnalysisFrame.java
 *
 *	Copyright (c) Manateem Challenge Group, Zaia Group, and contributors 2010
 *
 *	This file is part of MSGSwingSet ('this project').
 *	
 *	This project is free software: you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the Free
 *	Software Foundation, either version 3 of the License, or (at your option)
 *	any later version.
 *	
 *	This project is distributed in the hope that it will be useful, but WITHOUT
 *	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 *	more details.
 *	
 *	You should have received a copy of the GNU General Public License along with
 *	this project. If not, see <http://www.gnu.org/licenses/>.
 */
package edu.bu.manateem.msg.gui.analysis;

// Imports
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Set;

import javax.swing.*;

import edu.bu.manateem.msg.MSGConstants;
import edu.bu.manateem.msg.analysis.TargetedAbundanceAnalysis;
import edu.bu.manateem.msg.analysis.WidthPair;
import edu.bu.manateem.msg.analysis.io.AnalysisWriter;
import edu.bu.manateem.msg.analysis.io.TargetedAbundanceAnalysisArgs;
import edu.bu.manateem.msg.analysis.io.TargetedAbundanceAnalysisReader;
import edu.bu.manateem.msg.analysis.io.TargetedAbundanceAnalysisWriter;
import edu.bu.manateem.msg.gui.component.FileUploadPanel;
import edu.bu.manateem.msg.gui.component.MultiFileUploadPanel;
import edu.bu.manateem.msg.gui.component.NumberFieldFormItem;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *	<p>
 *	Targeted abundance analysis window (frame). Each new analysis invoked by at
 *	the main hub instantiates a new frame.
 *	</p>
 *
 *
 *	@author
 *		Christopher Jacobs
 *
 *	@version
 *		1.0
 *
 *	@changelog
 *		May 12, 2010	- Version 1.0.
 */
public class TargetedAbundanceAnalysisFrame
	extends JFrame
	implements AnalysisFrame,MouseListener
{
	/*
	 * TYPES
	 */

	/*
	 * CONSTANTS
	 */

	// Serialize
	private static final long serialVersionUID = 1L;
	// Logging
	private static final Logger LOG =
		LoggerFactory.getLogger(TargetedAbundanceAnalysisFrame.class);
	
	// Allowable file types
	private static final String[] RAW_FILE_TYPES =
		{
			"mzXML"
		};
	private static final String[] TARGET_FILE_TYPES =
		{
			"txt","tsv","gtf"
		};
	
	// Action commands
	private static final String LOAD = "load";
	private static final String SAVE = "save";
	private static final String RUN = "run";
	
	// Layout properties
	private static final int FRAME_DEFAULT_WIDTH =
		MSGConstants.SCREEN_SIZE.width / 2;
	private static final int FRAME_DEFAULT_HEIGHT =
		MSGConstants.SCREEN_SIZE.height / 2;
	private static final int FRAME_DEFAULT_OFFSET_X =
		MSGConstants.SCREEN_SIZE.width / 4;
	private static final int FRAME_DEFAULT_OFFSET_Y =
		MSGConstants.SCREEN_SIZE.height / 10;
	private static final Dimension FRAME_DEFAULT_SIZE =
		new Dimension(TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_WIDTH,
			TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_HEIGHT);
	private static final Point FRAME_DEFAULT_OFFSET =
		new Point(TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_OFFSET_X,
			TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_OFFSET_Y);
	
	private static final int X_SPACE_BETWEEN_COMPONENTS = 10;
	private static final int Y_SPACE_BETWEEN_COMPONENTS = 10;
	@SuppressWarnings("unused")
	private static final Dimension SPACE_BETWEEN_COMPONENTS =
		new Dimension(
			TargetedAbundanceAnalysisFrame.X_SPACE_BETWEEN_COMPONENTS,
			TargetedAbundanceAnalysisFrame.Y_SPACE_BETWEEN_COMPONENTS);
	
	private static final int BORDER_SIZE_TOP = 15;
	private static final int BORDER_SIZE_BOTTOM = 5;
	private static final int BORDER_SIZE_LEFT = 10;
	private static final int BORDER_SIZE_RIGHT = 10;
	
	/*
	 * FIELDS
	 */

	private MultiFileUploadPanel rawdataUploadPanel;
	private FileUploadPanel targetUploadPanel;
	private JPanel optionsPanel;
	
	private NumberFieldFormItem mzSumLeftItem =
		new NumberFieldFormItem("m/z Sum Width (Left)","",10,5);
	private NumberFieldFormItem mzSumRightItem =
		new NumberFieldFormItem("m/z Sum Width (Right)","",10,5);
	private NumberFieldFormItem rtSumItem =
		new NumberFieldFormItem("R.T. Sum Width","seconds",10,2);
	private NumberFieldFormItem rtSearchItem =
		new NumberFieldFormItem("R.T. Search Width","seconds",10,2);
	private JToolBar toolBar;
	
	private Set<String> parameterFiles = new HashSet<String>();
	
	/**
	 *	<p>
	 *	Basic constructor. Creates an instance of this object using only the
	 *	default parameters.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	public TargetedAbundanceAnalysisFrame()
	{
		super();
		
		TargetedAbundanceAnalysisFrame.LOG.debug("init self");
		
		initRawDataPanel();
		initTargetPanel();
		initOptionsPanel();
		initTools();
		init();
	}
	
	// private JToolBar toolBar;
	
	/*
	 * CONSTRUCTORS
	 */

	/*
	 * INITIALIZERS
	 */

	/*
	 * METHODS
	 */

	/**
	 *	<p>
	 *	Initializes the "master" frame of <code>this</code> object. Sets the
	 *	default frame behaviors and layout, and packs components.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	private void init()
	{
		TargetedAbundanceAnalysisFrame.LOG.debug("build container");
		
		// behaviors
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		setTitle("Targeted Abundance Analysis");
		setVisible(true);
		
		// layout
		GridBagLayout layout = new GridBagLayout();
		
		JPanel masterPanel = new JPanel();
		masterPanel.setBorder(BorderFactory.createEmptyBorder(
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_TOP,
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_LEFT,
			TargetedAbundanceAnalysisFrame.Y_SPACE_BETWEEN_COMPONENTS,
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_RIGHT));
		masterPanel.setLayout(layout);
		
		GridBagConstraints constraints = new GridBagConstraints();
		
		constraints.anchor = GridBagConstraints.FIRST_LINE_START;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.gridwidth = 1;
		constraints.gridx = 0;
		constraints.gridy = 1;
		constraints.weightx = 1;
		masterPanel.add(rawdataUploadPanel,constraints);
		
		constraints.gridy = 0;
		constraints.weightx = 0;
		masterPanel.add(new JLabel("<HTML><H3>Raw File(s):</H3></HTML>"),
			constraints);
		constraints.gridy = 2;
		masterPanel.add(new JLabel("<HTML><H3>Targets File:</H3></HTML>"),
			constraints);
		constraints.gridy = 3;
		masterPanel.add(targetUploadPanel,constraints);
		constraints.gridy = 4;
		masterPanel.add(new JLabel("<HTML><H3>Analysis Options</H3></HTML>"),
			constraints);
		constraints.fill = GridBagConstraints.NONE;
		constraints.gridy = 5;
		masterPanel.add(optionsPanel,constraints);
		
		setLocation(TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_OFFSET);
		setPreferredSize(TargetedAbundanceAnalysisFrame.FRAME_DEFAULT_SIZE);
		
		// finish
		getContentPane().add(masterPanel);
		add(toolBar,BorderLayout.PAGE_END);
		pack();
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build container -- DONE");
	}
	
	private void initOptionsPanel()
	{
		// build components
		TargetedAbundanceAnalysisFrame.LOG.debug("build mz sum width form item");
		mzSumLeftItem.setAlignmentX(Component.LEFT_ALIGNMENT);
		mzSumLeftItem.setAlignmentY(Component.TOP_ALIGNMENT);
		mzSumLeftItem.setColumns(5);
		mzSumLeftItem.setToolTipText("Width of the summation curve in mass-to-charge-space");
		mzSumLeftItem.setValue(TargetedAbundanceAnalysis.DEFAULT_MZ_SUMWIDTH);
		TargetedAbundanceAnalysisFrame.LOG.debug("build mz sum width form item -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build mz sum width form item");
		mzSumRightItem.setAlignmentX(Component.LEFT_ALIGNMENT);
		mzSumRightItem.setAlignmentY(Component.TOP_ALIGNMENT);
		mzSumRightItem.setColumns(5);
		mzSumRightItem.setToolTipText("Width of the summation curve in mass-to-charge-space");
		mzSumRightItem.setValue(TargetedAbundanceAnalysis.DEFAULT_MZ_SUMWIDTH);
		TargetedAbundanceAnalysisFrame.LOG.debug("build mz sum width form item -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build r.t. sum width form item");
		rtSumItem.setAlignmentX(Component.LEFT_ALIGNMENT);
		rtSumItem.setAlignmentY(Component.TOP_ALIGNMENT);
		rtSumItem.setColumns(5);
		rtSumItem.setToolTipText("Width of the summation curve in time-space");
		rtSumItem.setValue(TargetedAbundanceAnalysis.DEFAULT_RT_SUMWIDTH);
		TargetedAbundanceAnalysisFrame.LOG.debug("build mz sum width form item -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build r.t. search width form item");
		rtSearchItem.setAlignmentX(Component.LEFT_ALIGNMENT);
		rtSearchItem.setAlignmentY(Component.TOP_ALIGNMENT);
		rtSearchItem.setColumns(5);
		rtSearchItem.setToolTipText("Width of the search curve in time-space");
		rtSearchItem.setValue(TargetedAbundanceAnalysis.DEFAULT_RT_SEARCHWIDTH);
		TargetedAbundanceAnalysisFrame.LOG.debug("build r.t. search width form item -- DONE");
		
		// build panel
		TargetedAbundanceAnalysisFrame.LOG.debug("build options panel");
		optionsPanel = new JPanel();
		optionsPanel.setLayout(new BoxLayout(optionsPanel,BoxLayout.PAGE_AXIS));
		
		optionsPanel.add(mzSumLeftItem);
		optionsPanel.add(mzSumRightItem);
		optionsPanel.add(rtSumItem);
		optionsPanel.add(rtSearchItem);
		TargetedAbundanceAnalysisFrame.LOG.debug("build options panel -- DONE");
	}
	
	/**
	 *	<p>
	 *	Initializes the raw data file uploader for <code>this</code> object.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	private void initRawDataPanel()
	{
		// build components
		
		// build panel
		TargetedAbundanceAnalysisFrame.LOG.debug("build raw data upload panel");
		rawdataUploadPanel = new MultiFileUploadPanel();
		rawdataUploadPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
		rawdataUploadPanel.setAlignmentY(Component.TOP_ALIGNMENT);
		rawdataUploadPanel.setFileFilter("mzXML",
			TargetedAbundanceAnalysisFrame.RAW_FILE_TYPES);
		rawdataUploadPanel.setFont(MSGConstants.DEFAULT_FONT);
		TargetedAbundanceAnalysisFrame.LOG.debug("build raw data upload panel -- DONE");
	}
	
	/**
	 *	<p>
	 *	Initializes the target file uploader for <code>this</code> object.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	private void initTargetPanel()
	{
		// build components
		
		// build panel
		TargetedAbundanceAnalysisFrame.LOG.debug("build target upload panel");
		targetUploadPanel = new FileUploadPanel();
		targetUploadPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
		targetUploadPanel.setAlignmentY(Component.TOP_ALIGNMENT);
		targetUploadPanel.setFileFilter("Tab-Delimited",
			TargetedAbundanceAnalysisFrame.TARGET_FILE_TYPES);
		TargetedAbundanceAnalysisFrame.LOG.debug("build target upload panel -- DONE");
	}
	
	private void initTools()
	{
		// build text field
		TargetedAbundanceAnalysisFrame.LOG.debug("build save/load combo box");
		final JComboBox taaComboBox =
			new JComboBox(new String[]
				{
					AnalysisWriter.PARENT_DIR + MSGConstants.FILE_SEPARATOR
						+ "default.txt"
				});
		parameterFiles.add(AnalysisWriter.PARENT_DIR
			+ MSGConstants.FILE_SEPARATOR + "default.txt");
		taaComboBox.setEditable(true);
		taaComboBox.setFont(MSGConstants.DEFAULT_FONT);
		taaComboBox.setMaximumSize(new Dimension(
			MSGConstants.SCREEN_SIZE.width / 4,25));
		TargetedAbundanceAnalysisFrame.LOG.debug("build save/load combo box -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build save/load field");
		final JTextField taaNameField = new JTextField("");
		taaNameField.setFont(MSGConstants.DEFAULT_FONT);
		taaNameField.setMaximumSize(new Dimension(
			MSGConstants.SCREEN_SIZE.width / 4,25));
		TargetedAbundanceAnalysisFrame.LOG.debug("build save/load field -- DONE");
		
		// build "buttons"
		TargetedAbundanceAnalysisFrame.LOG.debug("build clear \"button\"");
		JLabel clearLabel =
			new JLabel(
				"<HTML><B><U><FONT color=blue>Clear</FONT></U></B></HTML>");
		clearLabel.addMouseListener(this);
		clearLabel.setToolTipText("Clear analysis parameters");
		TargetedAbundanceAnalysisFrame.LOG.debug("build clear \"button\" -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build load button");
		JButton loadButton = new JButton("Load...");
		loadButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// parse file
				String fileName = taaComboBox.getSelectedItem().toString();
				TargetedAbundanceAnalysisArgs args =
					TargetedAbundanceAnalysisReader.readFile(fileName);
				
				// set files
				rawdataUploadPanel.clearAll();
				for (String rawFileName : args.getRawFiles())
				{
					rawdataUploadPanel.addFile(rawFileName);
				}
				targetUploadPanel.clear();
				targetUploadPanel.addFile(args.getTargetFile());
				
				// set options
				mzSumLeftItem.setValue(args.getMZSumWidth().left);
				mzSumRightItem.setValue(args.getMZSumWidth().right);
				rtSumItem.setValue(args.getRTSumWidth().left);
				rtSearchItem.setValue(args.getRTSearchWidth().left);
			}
		});
		loadButton.setActionCommand(TargetedAbundanceAnalysisFrame.LOAD);
		loadButton.setFont(MSGConstants.BOLD_FONT);
		loadButton.setToolTipText("currently unsupported feature");
		TargetedAbundanceAnalysisFrame.LOG.debug("build load button -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build save button");
		JButton saveButton = new JButton("Save");
		saveButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// add to saved files
				String fileName = taaComboBox.getSelectedItem().toString();
				if (!parameterFiles.contains(fileName))
				{
					parameterFiles.add(fileName);
					taaComboBox.addItem(taaComboBox.getSelectedItem());
				}
				
				// save file
				WidthPair mzSum =
					new WidthPair(mzSumLeftItem.getValue().doubleValue(),
						mzSumRightItem.getValue().doubleValue());
				WidthPair rtSum =
					new WidthPair(rtSumItem.getValue().doubleValue(),
						rtSumItem.getValue().doubleValue());
				WidthPair rtSearch =
					new WidthPair(rtSearchItem.getValue().doubleValue(),
						rtSearchItem.getValue().doubleValue());
				try
				{
					TargetedAbundanceAnalysisWriter.generateParameterFile(
						fileName,rawdataUploadPanel.getCanonicalPaths(),
						targetUploadPanel.getCanonicalPath(),mzSum,rtSum,
						rtSearch);
				}
				catch (FileNotFoundException x)
				{
					// nothing
				}
			}
		});
		saveButton.setActionCommand(TargetedAbundanceAnalysisFrame.SAVE);
		saveButton.setFont(MSGConstants.BOLD_FONT);
		saveButton.setToolTipText("currently unsupported feature");
		TargetedAbundanceAnalysisFrame.LOG.debug("build save button -- DONE");
		
		TargetedAbundanceAnalysisFrame.LOG.debug("build run button");
		final JButton runButton = new JButton("Run!");
		runButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				runButton.setEnabled(false);
				WidthPair mzSum =
					new WidthPair(mzSumLeftItem.getValue().doubleValue(),
						mzSumRightItem.getValue().doubleValue());
				WidthPair rtSum =
					new WidthPair(rtSumItem.getValue().doubleValue(),
						rtSumItem.getValue().doubleValue());
				WidthPair rtSearch =
					new WidthPair(rtSearchItem.getValue().doubleValue(),
						rtSearchItem.getValue().doubleValue());
				String val =
					TargetedAbundanceAnalysis.runAnalysis(
						rawdataUploadPanel.getCanonicalPaths(),
						targetUploadPanel.getCanonicalPath(),mzSum,rtSum,
						rtSearch);
				JOptionPane.showMessageDialog(null,val);
				runButton.setEnabled(true);
			}
		});
		runButton.setActionCommand(TargetedAbundanceAnalysisFrame.RUN);
		runButton.setFont(MSGConstants.BOLD_FONT);
		runButton.setToolTipText("Run this analysis");
		TargetedAbundanceAnalysisFrame.LOG.debug("build run button -- DONE");
		
		// build tool bar
		TargetedAbundanceAnalysisFrame.LOG.debug("build tool bar");
		toolBar =
			new JToolBar("Targeted Abundance Analysis Toolbar",
				SwingConstants.HORIZONTAL);
		toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
		toolBar.setAlignmentY(Component.BOTTOM_ALIGNMENT);
		toolBar.setBorder(BorderFactory.createEmptyBorder(
			TargetedAbundanceAnalysisFrame.Y_SPACE_BETWEEN_COMPONENTS,
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_LEFT,
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_BOTTOM,
			TargetedAbundanceAnalysisFrame.BORDER_SIZE_RIGHT));
		toolBar.setLayout(new GridBagLayout());
		toolBar.setMaximumSize(new Dimension(MSGConstants.SCREEN_SIZE.width,25));
		
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.anchor = GridBagConstraints.CENTER;
		constraints.fill = GridBagConstraints.BOTH;
		constraints.gridwidth = 5;
		constraints.gridx = 4;
		constraints.gridy = 0;
		constraints.weightx = 0.5;
		// toolBar.add(taaNameField,constraints);
		toolBar.add(taaComboBox,constraints);
		
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.gridwidth = 3;
		constraints.gridx = 0;
		constraints.weightx = 0;
		toolBar.add(clearLabel,constraints);
		
		constraints.gridwidth = 1;
		constraints.gridx = 1;
		toolBar.add(new JToolBar.Separator(new Dimension(50,0)),constraints);
		constraints.gridx = 2;
		toolBar.add(new JToolBar.Separator(new Dimension(50,0)),constraints);
		constraints.gridx = 10;
		toolBar.add(new JToolBar.Separator(new Dimension(50,0)),constraints);
		
		constraints.gridx = 3;
		toolBar.add(loadButton,constraints);
		
		constraints.gridx = 9;
		toolBar.add(saveButton,constraints);
		
		constraints.gridx = 11;
		toolBar.add(runButton,constraints);
		TargetedAbundanceAnalysisFrame.LOG.debug("build tool bar -- DONE");
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public void mouseClicked(MouseEvent e)
	{
		TargetedAbundanceAnalysisFrame.LOG.info("mouse clicked on -- {}",
			e.getSource().getClass());
		rawdataUploadPanel.clearAll();
		targetUploadPanel.clear();
		mzSumLeftItem.setValue(TargetedAbundanceAnalysis.DEFAULT_MZ_SUMWIDTH);
		mzSumRightItem.setValue(TargetedAbundanceAnalysis.DEFAULT_MZ_SUMWIDTH);
		rtSumItem.setValue(TargetedAbundanceAnalysis.DEFAULT_RT_SUMWIDTH);
		rtSearchItem.setValue(TargetedAbundanceAnalysis.DEFAULT_RT_SEARCHWIDTH);
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public void mouseEntered(MouseEvent e)
	{
		// nothing
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public void mouseExited(MouseEvent e)
	{
		// nothing
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public void mousePressed(MouseEvent e)
	{
		// nothing
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public void mouseReleased(MouseEvent e)
	{
		// nothing
	}
}
